home *** CD-ROM | disk | FTP | other *** search
- // $Id: body.cpp,v 1.21 1999/08/26 15:34:02 shields Exp $
- //
- // This software is subject to the terms of the IBM Jikes Compiler
- // License Agreement available at the following URL:
- // http://www.ibm.com/research/jikes.
- // Copyright (C) 1996, 1998, International Business Machines Corporation
- // and others. All Rights Reserved.
- // You must accept the terms of that agreement to use this software.
- //
-
- #include "config.h"
- #include <assert.h>
- #include "semantic.h"
- #include "control.h"
-
- void Semantic::ProcessBlockStatements(AstBlock *block_body)
- {
- //
- // An empty block that is not a switch block can complete normally
- // iff it is reachable. A nonempty block that is not a switch
- // block can complete normally iff the last statement in it can
- // complete normally.
- //
- if (block_body -> NumStatements() == 0)
- block_body -> can_complete_normally = block_body -> is_reachable;
- else
- {
- //
- // The first statement in a nonempty block that is not a
- // switch block is reachable iff the block is reachable.
- // Every other statement S in a nonempty block that is not a
- // switch block is reachable iff the statement preceeding S
- // can complete normally.
- //
- AstStatement *statement = (AstStatement *) block_body -> Statement(0);
- statement -> is_reachable = block_body -> is_reachable;
- AstStatement *first_unreachable_statement = (AstStatement *) (statement -> is_reachable ? NULL : statement);
- ProcessStatement(statement);
- for (int i = 1; i < block_body -> NumStatements(); i++)
- {
- AstStatement *previous_statement = statement;
- statement = (AstStatement *) block_body -> Statement(i);
- statement -> is_reachable = previous_statement -> can_complete_normally;
- if (! statement -> is_reachable && (first_unreachable_statement == NULL))
- first_unreachable_statement = statement;
-
- ProcessStatement(statement);
- }
-
- if (statement -> can_complete_normally)
- block_body -> can_complete_normally = true;
-
- //
- // If we have one or more unreachable statements that are contained in a
- // reachable block then issue message. (If the enclosing block is not reachable
- // the message will be issued later for the enclosing block.)
- //
- if (first_unreachable_statement && LocalBlockStack().TopBlock() -> is_reachable)
- {
- if (first_unreachable_statement == statement)
- {
- ReportSemError(SemanticError::UNREACHABLE_STATEMENT,
- statement -> LeftToken(),
- statement -> RightToken());
- }
- else
- {
- ReportSemError(SemanticError::UNREACHABLE_STATEMENTS,
- first_unreachable_statement -> LeftToken(),
- statement -> RightToken());
- }
- }
-
- //
- // If an enclosed block has a higher max_variable_index than the current block,
- // update max_variable_index in the current_block, accordingly.
- //
- BlockSymbol *block = block_body -> block_symbol;
- if (block -> max_variable_index < LocalBlockStack().TopMaxEnclosedVariableIndex())
- block -> max_variable_index = LocalBlockStack().TopMaxEnclosedVariableIndex();
- }
-
- return;
- }
-
-
- void Semantic::ProcessBlock(Ast *stmt)
- {
- AstBlock *block_body = (AstBlock *) stmt;
-
- AstBlock *enclosing_block = LocalBlockStack().TopBlock();
-
- //
- // Guess that the number of elements will not exceed the number of statements + 3. The +3 takes into account
- // one label + one ForInit declaration and one extra something else.
- //
- int table_size = block_body -> NumStatements() + 3;
- BlockSymbol *block = LocalSymbolTable().Top() -> InsertBlockSymbol(table_size);
- //
- // enclosing_block is not present only when we are processing the block of a static initializer
- //
- block -> max_variable_index = (enclosing_block ? enclosing_block -> block_symbol -> max_variable_index : 1);
- LocalSymbolTable().Push(block -> Table());
-
- block_body -> block_symbol = block;
- block_body -> nesting_level = LocalBlockStack().Size();
- LocalBlockStack().Push(block_body);
-
- //
- // Note that in constructing the Ast, the parser encloses each
- // labeled statement in its own block. Therefore the declaration
- // of this label will not conflict with the declaration of another
- // label with the same name declared at the same nesting level.
- //
- // For example, the following sequence of statements is legal:
- //
- // l: a = b;
- // l: b = c;
- //
- for (int i = 0; i < block_body -> NumLabels(); i++)
- {
- NameSymbol *name_symbol = lex_stream -> NameSymbol(block_body -> Label(i));
- Symbol *symbol = NULL;
- for (SemanticEnvironment *env = state_stack.Top(); env; env = env -> previous)
- {
- symbol = env -> symbol_table.FindLabelSymbol(name_symbol);
- if (symbol)
- break;
- }
-
- if (symbol)
- {
- ReportSemError(SemanticError::DUPLICATE_LABEL,
- block_body -> Label(i),
- block_body -> Label(i),
- name_symbol -> Name());
- }
- else
- {
- LabelSymbol *label = LocalSymbolTable().Top() -> InsertLabelSymbol(name_symbol);
- label -> block = block_body;
- label -> nesting_level = block_body -> nesting_level;
- }
- }
-
- ProcessBlockStatements(block_body);
-
- LocalBlockStack().Pop();
- LocalSymbolTable().Pop();
-
- //
- // Update the information for the block that immediately encloses the current block.
- //
- if (enclosing_block)
- {
- if (LocalBlockStack().TopMaxEnclosedVariableIndex() < block -> max_variable_index)
- LocalBlockStack().TopMaxEnclosedVariableIndex() = block -> max_variable_index;
- }
-
- block -> CompressSpace(); // space optimization
-
- return;
- }
-
-
- void Semantic::ProcessLocalVariableDeclarationStatement(Ast *stmt)
- {
- AstLocalVariableDeclarationStatement *local_decl = (AstLocalVariableDeclarationStatement *) stmt;
-
- AstArrayType *array_type = local_decl -> type -> ArrayTypeCast();
- Ast *actual_type = (array_type ? array_type -> type : local_decl -> type);
-
- if ((! control.option.one_one) && local_decl -> NumLocalModifiers() > 0)
- {
- ReportSemError(SemanticError::ONE_ONE_FEATURE,
- local_decl -> LocalModifier(0) -> LeftToken(),
- local_decl -> LocalModifier(local_decl -> NumLocalModifiers() - 1) -> RightToken());
- }
- AccessFlags access_flags = ProcessLocalModifiers(local_decl);
-
- AstPrimitiveType *primitive_type = actual_type -> PrimitiveTypeCast();
- TypeSymbol *field_type = (primitive_type ? field_type = FindPrimitiveType(primitive_type) : MustFindType(actual_type));
-
- for (int i = 0; i < local_decl -> NumVariableDeclarators(); i++)
- {
- AstVariableDeclarator *variable_declarator = local_decl -> VariableDeclarator(i);
- AstVariableDeclaratorId *name = variable_declarator -> variable_declarator_name;
- NameSymbol *name_symbol = lex_stream -> NameSymbol(name -> identifier_token);
-
- //
- // TODO: Confirm that this new test is indeed the case. In 1.0, only the more restricted test below was necessary.
- //
- // if (LocalSymbolTable().FindVariableSymbol(name_symbol))
- // {
- // ReportSemError(SemanticError::DUPLICATE_LOCAL_VARIABLE_DECLARATION,
- // name -> identifier_token,
- // name -> identifier_token,
- // name_symbol -> Name());
- // }
- //
- SemanticEnvironment *where_found;
- Tuple<VariableSymbol *> variables_found(2);
- SearchForVariableInEnvironment(variables_found, where_found, state_stack.Top(), name_symbol, name -> identifier_token);
- VariableSymbol *symbol = (variables_found.Length() > 0 ? variables_found[0] : (VariableSymbol *) NULL);
- if (symbol && symbol -> IsLocal())
- {
- ReportSemError(SemanticError::DUPLICATE_LOCAL_VARIABLE_DECLARATION,
- name -> identifier_token,
- name -> identifier_token,
- name_symbol -> Name());
- }
- else
- {
- symbol = LocalSymbolTable().Top() -> InsertVariableSymbol(name_symbol);
- variable_declarator -> symbol = symbol;
-
- int num_dimensions = (array_type ? array_type -> NumBrackets() : 0) + name -> NumBrackets();
- if (num_dimensions == 0)
- symbol -> SetType(field_type);
- else symbol -> SetType(field_type -> GetArrayType((Semantic *) this, num_dimensions));
- symbol -> SetFlags(access_flags);
- symbol -> SetOwner(ThisMethod());
- symbol -> declarator = variable_declarator;
- BlockSymbol *block = LocalBlockStack().TopBlock() -> block_symbol;
- symbol -> SetLocalVariableIndex(block -> max_variable_index++); // Assigning a local_variable_index to a variable
- // also marks it complete as a side-effect.
- if (control.IsDoubleWordType(symbol -> Type()))
- block -> max_variable_index++;
-
- if (variable_declarator -> variable_initializer_opt)
- ProcessVariableInitializer(variable_declarator);
- }
- }
-
- //
- // A local variable declaration statement can complete normally
- // iff it is reachable.
- //
- local_decl -> can_complete_normally = local_decl -> is_reachable;
-
- return;
- }
-
-
- void Semantic::ProcessExpressionStatement(Ast *stmt)
- {
- AstExpressionStatement *expression_statement = (AstExpressionStatement *) stmt;
-
- ProcessExpression(expression_statement -> expression);
-
- //
- // An expression statement can complete normally iff it is reachable.
- //
- expression_statement -> can_complete_normally = expression_statement -> is_reachable;
-
- return;
- }
-
-
- void Semantic::ProcessSynchronizedStatement(Ast *stmt)
- {
- AstSynchronizedStatement *synchronized_statement = (AstSynchronizedStatement *) stmt;
-
- ProcessExpression(synchronized_statement -> expression);
-
- synchronized_statement -> block -> is_reachable = synchronized_statement -> is_reachable;
-
- if (synchronized_statement -> expression -> Type() -> Primitive())
- {
- ReportSemError(SemanticError::TYPE_NOT_REFERENCE,
- synchronized_statement -> expression -> LeftToken(),
- synchronized_statement -> expression -> RightToken(),
- synchronized_statement -> expression -> Type() -> Name());
- }
-
- AstBlock *enclosing_block = LocalBlockStack().TopBlock(),
- *block_body = synchronized_statement -> block;
-
- //
- // Guess that the number of elements will not exceed the number of statements + 3.
- //
- BlockSymbol *block = LocalSymbolTable().Top() -> InsertBlockSymbol(block_body -> NumStatements() + 3);
- //
- // "synchronized" blocks require two more local variable slots for synchronization,
- // plus one extra variable slot if the containing method returns a value, plus an
- // additional slot if the value returned is double or long.
- //
- block -> synchronized_variable_index = enclosing_block -> block_symbol -> max_variable_index;
- block -> max_variable_index = block -> synchronized_variable_index + 2;
- if (control.IsDoubleWordType(ThisMethod() -> Type()))
- block -> max_variable_index += 2;
- else if (ThisMethod() -> Type() != control.void_type)
- block -> max_variable_index++;
-
- LocalSymbolTable().Push(block -> Table());
-
- block_body -> block_symbol = block;
- block_body -> nesting_level = LocalBlockStack().Size();
- LocalBlockStack().Push(block_body);
-
- ProcessBlockStatements(block_body);
-
- LocalBlockStack().Pop();
- LocalSymbolTable().Pop();
-
- if (LocalBlockStack().TopMaxEnclosedVariableIndex() < block -> max_variable_index)
- LocalBlockStack().TopMaxEnclosedVariableIndex() = block -> max_variable_index;
-
- //
- // If the synchronized_statement is enclosed in a loop and it contains a reachable continue statement
- // then it may have already been marked as "can complete normally";
- //
- synchronized_statement -> can_complete_normally = synchronized_statement -> can_complete_normally ||
- synchronized_statement -> block -> can_complete_normally;
-
- block -> CompressSpace(); // space optimization
-
- return;
- }
-
-
- void Semantic::ProcessIfStatement(Ast *stmt)
- {
- AstIfStatement *if_statement = (AstIfStatement *) stmt;
-
- ProcessExpression(if_statement -> expression);
-
- if (if_statement -> expression -> Type() != control.no_type &&
- if_statement -> expression -> Type() != control.boolean_type)
- {
- ReportSemError(SemanticError::TYPE_NOT_BOOLEAN,
- if_statement -> expression -> LeftToken(),
- if_statement -> expression -> RightToken(),
- if_statement -> expression -> Type() -> Name());
- }
-
- //
- // Recall that the parser ensures that the statements that appear in an if-statement
- // (both the true and false statement) are enclosed in a block.
- //
- if_statement -> true_statement -> is_reachable = if_statement -> is_reachable;
- ProcessBlock(if_statement -> true_statement);
-
- if (if_statement -> false_statement_opt)
- {
- if_statement -> false_statement_opt -> is_reachable = if_statement -> is_reachable;
- ProcessBlock(if_statement -> false_statement_opt);
-
- //
- // If the if_statement is enclosed in a loop and it contains a reachable continue statement
- // then it may have already been marked as "can complete normally";
- //
- if_statement -> can_complete_normally = if_statement -> can_complete_normally ||
- if_statement -> true_statement -> can_complete_normally ||
- if_statement -> false_statement_opt -> can_complete_normally;
- }
- else if_statement -> can_complete_normally = if_statement -> is_reachable;
-
- return;
- }
-
-
- void Semantic::ProcessWhileStatement(Ast *stmt)
- {
- AstWhileStatement *while_statement = (AstWhileStatement *) stmt;
-
- //
- // Recall that each while statement is enclosed in a unique block by the parser
- //
- BreakableStatementStack().Push(LocalBlockStack().TopBlock());
- ContinuableStatementStack().Push(LocalBlockStack().TopBlock());
-
- AstStatement *enclosed_statement = while_statement -> statement;
- enclosed_statement -> is_reachable = while_statement -> is_reachable;
-
- ProcessExpression(while_statement -> expression);
- if (while_statement -> expression -> Type() == control.boolean_type)
- {
- if (while_statement -> expression -> IsConstant())
- {
- IntLiteralValue *literal = (IntLiteralValue *) while_statement -> expression -> value;
- if (! literal -> value)
- {
- if (while_statement -> is_reachable)
- while_statement -> can_complete_normally = true;
- enclosed_statement -> is_reachable = false;
- }
- }
- else if (while_statement -> is_reachable)
- while_statement -> can_complete_normally = true;
- }
- else if (while_statement -> expression -> Type() != control.no_type)
- {
- ReportSemError(SemanticError::TYPE_NOT_BOOLEAN,
- while_statement -> expression -> LeftToken(),
- while_statement -> expression -> RightToken(),
- while_statement -> expression -> Type() -> Name());
- }
-
- ProcessStatement(enclosed_statement);
-
- if ((! enclosed_statement -> is_reachable) && (while_statement -> is_reachable))
- {
- ReportSemError(SemanticError::UNREACHABLE_STATEMENT,
- enclosed_statement -> LeftToken(),
- enclosed_statement -> RightToken());
- }
-
- //
- // If the while statement contained a reachable break statement,
- // then the while statement can complete normally. It is marked
- // here only for completeness, as marking the enclosing block is
- // enough to propagate the proper information upward.
- //
- AstBlock *block_body = (AstBlock *) BreakableStatementStack().Top();
- if (block_body -> can_complete_normally)
- while_statement -> can_complete_normally = true;
-
- BreakableStatementStack().Pop();
- ContinuableStatementStack().Pop();
-
- return;
- }
-
-
- void Semantic::ProcessForStatement(Ast *stmt)
- {
- AstForStatement *for_statement = (AstForStatement *) stmt;
-
- //
- // Note that in constructing the Ast, the parser encloses each
- // for-statement whose for-init-statements starts with a local
- // variable declaration in its own block. Therefore a redeclaration
- // of another local variable with the same name in a different loop
- // at the same nesting level will not cause any conflict.
- //
- // For example, the following sequence of statements is legal:
- //
- // for (int i = 0; i < 10; i++);
- // for (int i = 10; i < 20; i++);
- //
- for (int i = 0; i < for_statement -> NumForInitStatements(); i++)
- ProcessStatement(for_statement -> ForInitStatement(i));
-
- //
- // Recall that each for statement is enclosed in a unique block by the parser
- //
- BreakableStatementStack().Push(LocalBlockStack().TopBlock());
- ContinuableStatementStack().Push(LocalBlockStack().TopBlock());
-
- //
- // Assume that if the for_statement is reachable then its
- // contained statement is also reachable. If it turns out that the
- // condition (end) expression is a constant FALSE expression we will
- // change the assumption...
- //
- AstStatement *enclosed_statement = for_statement -> statement;
- enclosed_statement -> is_reachable = for_statement -> is_reachable;
-
- if (for_statement -> end_expression_opt)
- {
- ProcessExpression(for_statement -> end_expression_opt);
- if (for_statement -> end_expression_opt -> Type() == control.boolean_type)
- {
- if (for_statement -> end_expression_opt -> IsConstant())
- {
- IntLiteralValue *literal = (IntLiteralValue *) for_statement -> end_expression_opt -> value;
- if (! literal -> value)
- {
- if (for_statement -> is_reachable)
- for_statement -> can_complete_normally = true;
- enclosed_statement -> is_reachable = false;
- }
- }
- else if (for_statement -> is_reachable)
- for_statement -> can_complete_normally = true;
- }
- else if (for_statement -> end_expression_opt -> Type() != control.no_type)
- {
- ReportSemError(SemanticError::TYPE_NOT_BOOLEAN,
- for_statement -> end_expression_opt -> LeftToken(),
- for_statement -> end_expression_opt -> RightToken(),
- for_statement -> end_expression_opt -> Type() -> Name());
- }
- }
-
- ProcessStatement(enclosed_statement);
-
- if ((! enclosed_statement -> is_reachable) && (for_statement -> is_reachable))
- {
- ReportSemError(SemanticError::UNREACHABLE_STATEMENT,
- enclosed_statement -> LeftToken(),
- enclosed_statement -> RightToken());
- }
-
- for (int j = 0; j < for_statement -> NumForUpdateStatements(); j++)
- ProcessExpressionStatement(for_statement -> ForUpdateStatement(j));
-
- //
- // If the for statement contained a reachable break statement,
- // then the for statement can complete normally. It is marked
- // here only for completeness, as marking the enclosing block is
- // enough to propagate the proper information upward.
- //
- AstBlock *block_body = (AstBlock *) BreakableStatementStack().Top();
- if (block_body -> can_complete_normally)
- for_statement -> can_complete_normally = true;
-
- BreakableStatementStack().Pop();
- ContinuableStatementStack().Pop();
-
- return;
- }
-
-
- void Semantic::ProcessSwitchStatement(Ast *stmt)
- {
- AstSwitchStatement *switch_statement = (AstSwitchStatement *) stmt;
-
- AstBlock *enclosing_block = LocalBlockStack().TopBlock();
-
- //
- // We estimate a size for the switch symbol table based on the number of lines in it.
- //
- AstBlock *block_body = switch_statement -> switch_block;
- BlockSymbol *block = LocalSymbolTable().Top() -> InsertBlockSymbol();
- block -> max_variable_index = enclosing_block -> block_symbol -> max_variable_index;
- LocalSymbolTable().Push(block -> Table());
-
- block_body -> block_symbol = block;
- block_body -> nesting_level = LocalBlockStack().Size();
- LocalBlockStack().Push(block_body);
- BreakableStatementStack().Push(block_body);
-
- ProcessExpression(switch_statement -> expression);
- TypeSymbol *type = switch_statement -> expression -> Type();
-
- if (type != control.int_type && type != control.short_type &&
- type != control.char_type && type != control.byte_type && type != control.no_type)
- {
- ReportSemError(SemanticError::TYPE_NOT_VALID_FOR_SWITCH,
- switch_statement -> expression -> LeftToken(),
- switch_statement -> expression -> RightToken(),
- type -> ContainingPackage() -> PackageName(),
- type -> ExternalName());
- }
-
- switch_statement -> default_case.switch_block_statement = NULL;
-
- //
- // Count the number case labels in this switch statement
- //
- int num_case_labels = 0;
- for (int i = 0; i < block_body -> NumStatements(); i++)
- {
- AstSwitchBlockStatement *switch_block_statement = (AstSwitchBlockStatement *) block_body -> Statement(i);
- num_case_labels += switch_block_statement -> NumSwitchLabels();
- }
- switch_statement -> AllocateCases(num_case_labels);
-
- //
- // A switch block is reachable iff its switch statement is reachable.
- //
- block_body -> is_reachable = switch_statement -> is_reachable;
- for (int j = 0; j < block_body -> NumStatements(); j++)
- {
- AstSwitchBlockStatement *switch_block_statement = (AstSwitchBlockStatement *) block_body -> Statement(j);
-
- for (int k = 0; k < switch_block_statement -> NumSwitchLabels(); k++)
- {
- AstCaseLabel *case_label = switch_block_statement -> SwitchLabel(k) -> CaseLabelCast();
-
- if (case_label)
- {
- ProcessExpression(case_label -> expression);
-
- if (case_label -> expression -> Type() != control.no_type)
- {
- if (! case_label -> expression -> IsConstant())
- {
- ReportSemError(SemanticError::EXPRESSION_NOT_CONSTANT,
- case_label -> expression -> LeftToken(),
- case_label -> expression -> RightToken());
- case_label -> expression -> symbol = control.no_type;
- }
- else if (type != control.no_type)
- {
- if (CanAssignmentConvert(type, case_label -> expression))
- {
- if (case_label -> expression -> Type() != type)
- case_label -> expression = ConvertToType(case_label -> expression, type);
-
- case_label -> map_index = switch_statement -> NumCases();
-
- CaseElement *case_element = compilation_unit -> ast_pool -> GenCaseElement();
- switch_statement -> AddCase(case_element);
-
- case_element -> expression = case_label -> expression;
- case_element -> switch_block_statement = switch_block_statement;
- case_element -> index = case_label -> map_index; // use this index to keep sort stable !
- }
- else if (case_label -> expression -> Type() == control.int_type &&
- ! IsIntValueRepresentableInType(case_label -> expression, type))
- {
- IntToWstring value(((IntLiteralValue *) (case_label -> expression -> value)) -> value);
-
- ReportSemError(SemanticError::VALUE_NOT_REPRESENTABLE_IN_SWITCH_TYPE,
- case_label -> expression -> LeftToken(),
- case_label -> expression -> RightToken(),
- value.String(),
- type -> Name());
- }
- else
- {
- ReportSemError(SemanticError::TYPE_NOT_CONVERTIBLE_TO_SWITCH_TYPE,
- case_label -> expression -> LeftToken(),
- case_label -> expression -> RightToken(),
- case_label -> expression -> Type() -> Name(),
- type -> Name());
- }
- }
- }
- }
- else if (switch_statement -> default_case.switch_block_statement == NULL)
- switch_statement -> default_case.switch_block_statement = switch_block_statement;
- else
- {
- ReportSemError(SemanticError::MULTIPLE_DEFAULT_LABEL,
- ((AstDefaultLabel *) switch_block_statement -> SwitchLabel(k)) -> LeftToken(),
- ((AstDefaultLabel *) switch_block_statement -> SwitchLabel(k)) -> RightToken());
- }
- }
-
- //
- // The parser ensures that a switch block statement always has one statement.
- // When a switch block ends with a sequence of switch labels that are not followed
- // by any executable statements, an artificial "empty" statement is added by the parser.
- //
- assert(switch_block_statement -> NumStatements() > 0);
-
- //
- // A statement in a switch block is reachable iff its
- // switch statement is reachable and at least one of the
- // following is true:
- //
- // . it bears a case or default label
- // . there is a statement preceeding it in the switch block and that
- // preceeding statement can compile normally.
- //
- AstStatement *statement = (AstStatement *) switch_block_statement -> Statement(0);
- statement -> is_reachable = switch_statement -> is_reachable;
- AstStatement *first_unreachable_statement = (AstStatement *) (statement -> is_reachable ? NULL : statement);
- ProcessStatement(statement);
- for (int j = 1; j < switch_block_statement -> NumStatements(); j++)
- {
- AstStatement *previous_statement = statement;
- statement = (AstStatement *) switch_block_statement -> Statement(j);
- if (switch_statement -> is_reachable)
- {
- statement -> is_reachable = previous_statement -> can_complete_normally;
- if ((! statement -> is_reachable) && (first_unreachable_statement == NULL))
- first_unreachable_statement = statement;
- }
-
- ProcessStatement(statement);
- }
-
- if (first_unreachable_statement)
- {
- if (first_unreachable_statement == statement)
- {
- ReportSemError(SemanticError::UNREACHABLE_STATEMENT,
- statement -> LeftToken(),
- statement -> RightToken());
- }
- else
- {
- ReportSemError(SemanticError::UNREACHABLE_STATEMENTS,
- first_unreachable_statement -> LeftToken(),
- statement -> RightToken());
- }
- }
- }
-
- //
- // A switch statement can complete normally iff at least one of the
- // following is true:
- //
- // . there is a reachable break statement that exits the switch
- // statement. (See ProcessBreakStatement)
- // . the switch block is empty or contains only switch labels
- // //
- // // TODO: This statement seems to be erroneous. The proper statement
- // // as implemented here is:
- // //
- // // . the switch block is empty or contains only case labels
- // //
- // . there is at least one switch label after the last switch block
- // statement group.
- // . the last statement in the switch block can complete normally
- //
- if (block_body -> can_complete_normally)
- switch_statement -> can_complete_normally = true;
- else if (switch_statement -> default_case.switch_block_statement == NULL)
- switch_statement -> can_complete_normally = true;
- else
- {
- AstSwitchBlockStatement *last_switch_block_statement = (AstSwitchBlockStatement *)
- block_body -> Statement(block_body -> NumStatements() - 1);
-
- assert(last_switch_block_statement -> NumStatements() > 0);
-
- AstStatement *last_statement = (AstStatement *)
- last_switch_block_statement -> Statement(last_switch_block_statement -> NumStatements() - 1);
- if (last_statement -> can_complete_normally)
- switch_statement -> can_complete_normally = true;
- }
-
- switch_statement -> SortCases();
- for (int k = 1; k < switch_statement -> NumCases(); k++)
- {
- if (switch_statement -> Case(k) -> Value() == switch_statement -> Case(k - 1) -> Value())
- {
- IntToWstring value(switch_statement -> Case(k) -> Value());
-
- ReportSemError(SemanticError::DUPLICATE_CASE_VALUE,
- switch_statement -> Case(k) -> expression -> LeftToken(),
- switch_statement -> Case(k) -> expression -> RightToken(),
- value.String());
- }
- }
-
- //
- // If an enclosed block has a higher max_variable_index than the current block,
- // update max_variable_index in the current_block, accordingly.
- // Also, update the information for the block that immediately encloses the current block.
- //
- if (block -> max_variable_index < LocalBlockStack().TopMaxEnclosedVariableIndex())
- block -> max_variable_index = LocalBlockStack().TopMaxEnclosedVariableIndex();
-
- BreakableStatementStack().Pop();
- LocalBlockStack().Pop();
- LocalSymbolTable().Pop();
-
- if (enclosing_block)
- {
- if (LocalBlockStack().TopMaxEnclosedVariableIndex() < block -> max_variable_index)
- LocalBlockStack().TopMaxEnclosedVariableIndex() = block -> max_variable_index;
- }
-
- block -> CompressSpace(); // space optimization
-
- return;
- }
-
-
- void Semantic::ProcessDoStatement(Ast *stmt)
- {
- AstDoStatement *do_statement = (AstDoStatement *) stmt;
-
- //
- // Recall that each Do statement is enclosed in a unique block by the parser
- //
- BreakableStatementStack().Push(LocalBlockStack().TopBlock());
- ContinuableStatementStack().Push(LocalBlockStack().TopBlock());
-
- AstStatement *enclosed_statement = do_statement -> statement;
- enclosed_statement -> is_reachable = do_statement -> is_reachable;
-
- ProcessStatement(enclosed_statement);
-
- ProcessExpression(do_statement -> expression);
-
- IntLiteralValue *literal = NULL;
- if (do_statement -> expression -> Type() == control.boolean_type)
- {
- if (do_statement -> expression -> IsConstant())
- literal = (IntLiteralValue *) do_statement -> expression -> value;
- }
- else if (do_statement -> expression -> Type() != control.no_type)
- {
- ReportSemError(SemanticError::TYPE_NOT_BOOLEAN,
- do_statement -> expression -> LeftToken(),
- do_statement -> expression -> RightToken(),
- do_statement -> expression -> Type() -> Name());
- }
-
- //
- // A do statement can complete normally, iff at least one of the following is true:
- // 1. The contained statement can complete normally and the condition expression
- // is not a constant expression with the value true
- // 2. There is a reachable break statement that exits the do statement
- // (This condition is true is the block that immediately encloses this do statement
- // can complete normally. See ProcessBreakStatement)
- //
- AstBlock *block_body = (AstBlock *) BreakableStatementStack().Top();
- do_statement -> can_complete_normally = (enclosed_statement -> can_complete_normally && ((! literal) || literal -> value == 0)) ||
- block_body -> can_complete_normally;
-
- BreakableStatementStack().Pop();
- ContinuableStatementStack().Pop();
-
- return;
- }
-
-
- void Semantic::ProcessBreakStatement(Ast *stmt)
- {
- AstBreakStatement *break_statement = (AstBreakStatement *) stmt;
-
- //
- // Recall that it is possible to break out of any labeled statement even if it is not a
- // do, for, while or switch statement.
- //
- if (break_statement -> identifier_token_opt)
- {
- NameSymbol *name_symbol = lex_stream -> NameSymbol(break_statement -> identifier_token_opt);
- LabelSymbol *label_symbol = LocalSymbolTable().FindLabelSymbol(name_symbol);
-
- if (label_symbol)
- {
- break_statement -> nesting_level = label_symbol -> nesting_level;
- AstBlock *block_body = label_symbol -> block;
- //
- // A labeled statement can complete normally if there is a
- // reachable break statement that exits the labeled statement.
- //
- if (block_body && break_statement -> is_reachable)
- block_body -> can_complete_normally = true;
- }
- else
- {
- AstBlock *block_body = (AstBlock *) LocalBlockStack().TopBlock();
- break_statement -> nesting_level = block_body -> nesting_level;
- ReportSemError(SemanticError::UNDECLARED_LABEL,
- break_statement -> identifier_token_opt,
- break_statement -> identifier_token_opt,
- lex_stream -> NameString(break_statement -> identifier_token_opt));
- }
- }
- else
- {
- AstBlock *block_body = (AstBlock *) (BreakableStatementStack().Size() > 0 ? BreakableStatementStack().Top()
- : LocalBlockStack().TopBlock());
- break_statement -> nesting_level = block_body -> nesting_level;
- if (BreakableStatementStack().Size() > 0)
- {
- if (break_statement -> is_reachable)
- block_body -> can_complete_normally = true;
- }
- else ReportSemError(SemanticError::MISPLACED_BREAK_STATEMENT,
- break_statement -> LeftToken(),
- break_statement -> RightToken());
- }
-
- return;
- }
-
-
- void Semantic::ProcessContinueStatement(Ast *stmt)
- {
- AstContinueStatement *continue_statement = (AstContinueStatement *) stmt;
-
- //
- // The loop statement that is to be continued.
- //
- Ast *loop_statement = NULL;
-
- if (ContinuableStatementStack().Size() <= 0)
- {
- ReportSemError(SemanticError::MISPLACED_CONTINUE_STATEMENT,
- continue_statement -> LeftToken(),
- continue_statement -> RightToken());
- }
- else if (continue_statement -> identifier_token_opt)
- {
- NameSymbol *name_symbol = lex_stream -> NameSymbol(continue_statement -> identifier_token_opt);
- LabelSymbol *label_symbol = LocalSymbolTable().FindLabelSymbol(name_symbol);
-
- if (label_symbol)
- {
- continue_statement -> nesting_level = label_symbol -> nesting_level;
-
- assert(label_symbol -> block -> NumStatements() > 0);
-
- loop_statement = label_symbol -> block -> Statement(0);
- }
- else
- {
- AstBlock *block_body = (AstBlock *) LocalBlockStack().TopBlock();
- continue_statement -> nesting_level = block_body -> nesting_level;
- ReportSemError(SemanticError::UNDECLARED_LABEL,
- continue_statement -> identifier_token_opt,
- continue_statement -> identifier_token_opt,
- lex_stream -> NameString(continue_statement -> identifier_token_opt));
- }
- }
- else
- {
- AstBlock *block_body = (AstBlock *) ContinuableStatementStack().Top();
- loop_statement = block_body -> Statement(0);
- continue_statement -> nesting_level = block_body -> nesting_level;
- }
-
- //
- // If this is a valid continue statement, it is associated with a loop statement.
- // Since the loop can be continued, its enclosed statement "can complete normally".
- //
- if (loop_statement)
- {
- AstDoStatement *do_statement = loop_statement -> DoStatementCast();
- AstForStatement *for_statement = loop_statement -> ForStatementCast();
- AstWhileStatement *while_statement = loop_statement -> WhileStatementCast();
-
- AstStatement *enclosed_statement = (do_statement ? do_statement -> statement
- : (for_statement ? for_statement -> statement
- : (while_statement ? while_statement -> statement
- : (AstStatement *) NULL)));
- if (enclosed_statement)
- enclosed_statement -> can_complete_normally = true;
- else
- {
- assert(continue_statement -> identifier_token_opt);
-
- ReportSemError(SemanticError::INVALID_CONTINUE_TARGET,
- continue_statement -> LeftToken(),
- continue_statement -> RightToken(),
- lex_stream -> NameString(continue_statement -> identifier_token_opt));
- }
- }
-
- return;
- }
-
-
- void Semantic::ProcessReturnStatement(Ast *stmt)
- {
- AstReturnStatement *return_statement = (AstReturnStatement *) stmt;
-
- MethodSymbol *this_method = ThisMethod();
-
- if (this_method -> name_symbol == control.clinit_name_symbol || this_method -> name_symbol == control.block_init_name_symbol)
- {
- ReportSemError(SemanticError::RETURN_STATEMENT_IN_INITIALIZER,
- return_statement -> LeftToken(),
- return_statement -> RightToken());
- }
- else if (return_statement -> expression_opt)
- {
- ProcessExpression(return_statement -> expression_opt);
-
- if (this_method -> Type() == control.void_type)
- {
- ReportSemError(SemanticError::MISPLACED_RETURN_WITH_EXPRESSION,
- return_statement -> LeftToken(),
- return_statement -> RightToken());
- }
- else if (return_statement -> expression_opt -> Type() != control.no_type)
- {
- if (this_method -> Type() != return_statement -> expression_opt -> Type())
- {
- if (CanAssignmentConvert(this_method -> Type(), return_statement -> expression_opt))
- return_statement -> expression_opt = ConvertToType(return_statement -> expression_opt, this_method -> Type());
- else
- {
- ReportSemError(SemanticError::MISMATCHED_RETURN_AND_METHOD_TYPE,
- return_statement -> expression_opt -> LeftToken(),
- return_statement -> expression_opt -> RightToken(),
- return_statement -> expression_opt -> Type() -> ContainingPackage() -> PackageName(),
- return_statement -> expression_opt -> Type() -> ExternalName(),
- this_method -> Type() -> ContainingPackage() -> PackageName(),
- this_method -> Type() -> ExternalName());
- }
- }
- }
- }
- else if (this_method -> Type() != control.void_type)
- {
- ReportSemError(SemanticError::MISPLACED_RETURN_WITH_NO_EXPRESSION,
- return_statement -> LeftToken(),
- return_statement -> RightToken());
- }
-
- return;
- }
-
-
- bool Semantic::CatchableException(TypeSymbol *exception)
- {
- //
- // An unchecked exception or an error is ok !!
- //
- if (! CheckedException(exception) || exception == control.no_type)
- return true;
-
- //
- // Firstly, check the stack of try statements to see if the exception in question is catchable.
- //
- for (int i = TryStatementStack().Size() - 1; i >= 0; i--)
- {
- AstTryStatement *try_statement = (AstTryStatement *) TryStatementStack()[i];
-
- //
- // If a try statement contains a finally clause that can complete abruptly
- // then any exception that can reach it is assumed to be catchable.
- // See Spec 11.3.
- //
- if (try_statement -> finally_clause_opt && (! try_statement -> finally_clause_opt -> block -> can_complete_normally))
- return true;
-
- //
- // Check each catch clause in turn.
- //
- for (int k = 0; k < try_statement -> NumCatchClauses(); k++)
- {
- AstCatchClause *clause = try_statement -> CatchClause(k);
- VariableSymbol *symbol = clause -> parameter_symbol;
- if (CanAssignmentConvertReference(symbol -> Type(), exception))
- return true;
- }
- }
-
- //
- // If we are processing the initialization expression of a field,
- // ThisMethod() is not defined.
- //
- MethodSymbol *this_method = ThisMethod();
- if (this_method)
- {
- for (int l = this_method -> NumThrows() - 1; l >= 0; l--)
- {
- if (CanAssignmentConvertReference(this_method -> Throws(l), exception))
- return true;
- }
-
- if (this_method -> NumInitializerConstructors() > 0)
- {
- int j;
- for (j = this_method -> NumInitializerConstructors() - 1; j >= 0; j--)
- {
- MethodSymbol *method = this_method -> InitializerConstructor(j);
- int k;
- for (k = method -> NumThrows() - 1; k >= 0; k--)
- {
- if (CanAssignmentConvertReference(method -> Throws(k), exception))
- break;
- }
- if (k < 0) // no hit was found in method.
- return false;
- }
- if (j < 0) // all the relevant constructors can catch the exception
- return true;
- }
- }
-
- return false;
- }
-
-
- void Semantic::ProcessThrowStatement(Ast *stmt)
- {
- AstThrowStatement *throw_statement = (AstThrowStatement *) stmt;
-
- ProcessExpression(throw_statement -> expression);
- TypeSymbol *type = throw_statement -> expression -> Type();
-
- if (type != control.no_type && (! CanAssignmentConvertReference(control.Throwable(), type)))
- {
- ReportSemError(SemanticError::EXPRESSION_NOT_THROWABLE,
- throw_statement -> LeftToken(),
- throw_statement -> RightToken());
- }
-
- SymbolSet *exception_set = TryExceptionTableStack().Top();
- if (exception_set)
- exception_set -> AddElement(type);
-
- if (! CatchableException(type))
- {
- MethodSymbol *this_method = ThisMethod();
- MethodSymbol *method = (this_method && this_method -> Identity() != control.clinit_name_symbol
- && this_method -> Identity() != control.block_init_name_symbol
- ? this_method
- : (MethodSymbol *) NULL);
-
- if (TryStatementStack().Size() > 0)
- ReportSemError(SemanticError::BAD_THROWABLE_EXPRESSION_IN_TRY,
- throw_statement -> LeftToken(),
- throw_statement -> RightToken(),
- type -> ContainingPackage() -> PackageName(),
- type -> ExternalName(),
- (method ? method -> Header() : StringConstant::US_EMPTY));
- else if (method)
- ReportSemError(SemanticError::BAD_THROWABLE_EXPRESSION_IN_METHOD,
- throw_statement -> LeftToken(),
- throw_statement -> RightToken(),
- type -> ContainingPackage() -> PackageName(),
- type -> ExternalName(),
- method -> Header());
- else ReportSemError(SemanticError::BAD_THROWABLE_EXPRESSION,
- throw_statement -> LeftToken(),
- throw_statement -> RightToken(),
- type -> ContainingPackage() -> PackageName(),
- type -> ExternalName());
- }
-
- return;
- }
-
-
- void Semantic::ProcessTryStatement(Ast *stmt)
- {
- AstTryStatement *try_statement = (AstTryStatement *) stmt;
-
- //
- // A try_statement containing a finally clause requires some extra local
- // variables in its immediately enclosing block. If it is enclosed in a method
- // that returns void then 2 extra elements are needed. If the method
- // returns a long or a double value, two additional elements are needed.
- // Otherwise, one additional element is needed.
- // If this try_statement is the first try_statement with a finally clause
- // that was encountered in the immediately enclosing block, we allocate
- // two extra slots for the special local variables.
- //
- AstBlock *enclosing_block = LocalBlockStack().TopBlock();
- if (try_statement -> finally_clause_opt)
- {
- BlockSymbol *block = enclosing_block -> block_symbol;
- if (block -> try_variable_index == 0) // first try_statement encountered in enclosing block?
- {
- block -> try_variable_index = block -> max_variable_index;
- block -> max_variable_index += 2;
- if (ThisMethod() -> Type() != control.void_type)
- {
- if (control.IsDoubleWordType(ThisMethod() -> Type()))
- block -> max_variable_index += 2;
- else block -> max_variable_index += 1;
- }
- }
-
- //
- // A finally block is processed in the environment of its immediate enclosing block.
- // (as opposed to the environment of its associated try block).
- //
- // Note that the finally block must be processed prior to the other
- // blocks in the try statement, because the computation of whether or not
- // an exception is catchable in a try statement depends on the termination
- // status of the associated finally block. See CatchableException function.
- //
- AstBlock *block_body = try_statement -> finally_clause_opt -> block;
- block_body -> is_reachable = try_statement -> is_reachable;
- ProcessBlock(block_body);
- }
-
- //
- // Note that the catch clauses are processed first - prior to processing
- // the main block - so that we can have their parameters available when we
- // are processing the main block, in case that block contains a throw
- // statement. See ProcessThrowStatement for more information.
- //
- // Also, recall that the body of the catch blocks must not be
- // processed within the environment of the associated try whose
- // exceptions they are supposed to catch but within the immediate enclosing
- // block (which may itself be a try block).
- //
- for (int i = 0; i < try_statement -> NumCatchClauses(); i++)
- {
- AstCatchClause *clause = try_statement -> CatchClause(i);
- AstFormalParameter *parameter = clause -> formal_parameter;
-
- TypeSymbol *parm_type;
-
- if (parameter -> type -> PrimitiveTypeCast())
- {
- ReportSemError(SemanticError::CATCH_PRIMITIVE_TYPE,
- parameter -> LeftToken(),
- parameter -> RightToken());
- parm_type = control.Error();
- }
- else if (parameter -> type -> ArrayTypeCast())
- {
- ReportSemError(SemanticError::CATCH_ARRAY_TYPE,
- parameter -> LeftToken(),
- parameter -> RightToken());
- parm_type = control.Error();
- }
- else parm_type = MustFindType(parameter -> type);
-
- if (! parm_type -> IsSubclass(control.Throwable()))
- {
- ReportSemError(SemanticError::TYPE_NOT_THROWABLE,
- parameter -> LeftToken(),
- parameter -> RightToken(),
- parm_type -> ContainingPackage() -> PackageName(),
- parm_type -> ExternalName());
- }
-
- AstVariableDeclaratorId *name = parameter -> formal_declarator -> variable_declarator_name;
- NameSymbol *name_symbol = lex_stream -> NameSymbol(name -> identifier_token);
- if (LocalSymbolTable().FindVariableSymbol(name_symbol))
- {
- ReportSemError(SemanticError::DUPLICATE_LOCAL_VARIABLE_DECLARATION,
- name -> identifier_token,
- name -> identifier_token,
- name_symbol -> Name());
- }
-
- AstBlock *block_body = clause -> block;
- //
- // Guess that the number of elements in the table will not exceed the number of statements + the clause parameter.
- //
- BlockSymbol *block = LocalSymbolTable().Top() -> InsertBlockSymbol(block_body -> NumStatements() + 1);
- block -> max_variable_index = enclosing_block -> block_symbol -> max_variable_index;
- LocalSymbolTable().Push(block -> Table());
-
- if ((! control.option.one_one) && parameter -> NumParameterModifiers() > 0)
- {
- ReportSemError(SemanticError::ONE_ONE_FEATURE,
- parameter -> ParameterModifier(0) -> LeftToken(),
- parameter -> ParameterModifier(0) -> RightToken());
- }
- AccessFlags access_flags = ProcessFormalModifiers(parameter);
-
- VariableSymbol *symbol = LocalSymbolTable().Top() -> InsertVariableSymbol(name_symbol);
- symbol -> SetFlags(access_flags);
- symbol -> SetType(parm_type);
- symbol -> SetOwner(ThisMethod());
- symbol -> SetLocalVariableIndex(block -> max_variable_index++);
- symbol -> declarator = parameter -> formal_declarator;
-
- clause -> parameter_symbol = symbol;
-
- //
- // Note that for the purpose of semantic checking we assume that
- // the body of the catch block is reachable. Whether or not the catch
- // statement can be executed at all is checked later.
- //
- block_body -> is_reachable = true;
-
- block_body -> block_symbol = block;
- block_body -> nesting_level = LocalBlockStack().Size();
- LocalBlockStack().Push(block_body);
-
- ProcessBlockStatements(block_body);
-
- LocalBlockStack().Pop();
- LocalSymbolTable().Pop();
-
- //
- // Update the information for the block that immediately encloses the current block.
- //
- if (LocalBlockStack().TopMaxEnclosedVariableIndex() < block -> max_variable_index)
- LocalBlockStack().TopMaxEnclosedVariableIndex() = block -> max_variable_index;
-
- //
- // If a catch clause block can complete normally, we assume
- // that the try statement can complete normally. This may
- // prove to be false later if we find out that the finally
- // clause cannot complete normally...
- //
- if (block_body -> can_complete_normally)
- try_statement -> can_complete_normally = true;
-
- block -> CompressSpace(); // space optimization
- }
-
- //
- //
- //
- TryStatementStack().Push(try_statement);
- SymbolSet *exception_set = new SymbolSet;
- TryExceptionTableStack().Push(exception_set);
-
- try_statement -> block -> is_reachable = try_statement -> is_reachable;
- ProcessBlock(try_statement -> block);
- if (try_statement -> block -> can_complete_normally)
- try_statement -> can_complete_normally = true;
-
- //
- // A catch block is reachable iff both of the following are true:
- //
- // . Some expression or throw statement in the try block is reachable
- // and can throw an exception that is assignable to the parameter
- // of the catch clause C.
- //
- // . There is no earlier catch block A in the try statement such that the
- // type of C's parameter is the same as or a subclass of the type of A's
- // parameter.
- //
- Tuple<TypeSymbol *> thrown_exceptions;
- for (int l = 0; l < try_statement -> NumCatchClauses(); l++)
- {
- AstCatchClause *clause = try_statement -> CatchClause(l);
- VariableSymbol *symbol = clause -> parameter_symbol;
- if (CheckedException(symbol -> Type()))
- {
- int initial_length = thrown_exceptions.Length();
-
- for (TypeSymbol *exception = (TypeSymbol *) exception_set -> FirstElement();
- exception;
- exception = (TypeSymbol *) exception_set -> NextElement())
- {
- if (CanAssignmentConvertReference(symbol -> Type(), exception) ||
- CanAssignmentConvertReference(exception, symbol -> Type()))
- thrown_exceptions.Next() = exception;
- }
-
- if (thrown_exceptions.Length() == initial_length) // no assignable exception was found
- {
- ReportSemError(SemanticError::UNREACHABLE_CATCH_CLAUSE,
- clause -> formal_parameter -> LeftToken(),
- clause -> formal_parameter -> RightToken(),
- symbol -> Type() -> ContainingPackage() -> PackageName(),
- symbol -> Type() -> ExternalName());
- }
- else
- {
- //
- // TODO: I know, I know, this is a sequential search...
- //
- AstCatchClause *previous_clause;
- int k;
- for (k = 0; k < l; k++)
- {
- previous_clause = try_statement -> CatchClause(k);
- if (symbol -> Type() -> IsSubclass(previous_clause -> parameter_symbol -> Type()))
- break;
- }
-
- if (k < l)
- {
- FileLocation loc(lex_stream, previous_clause -> formal_parameter -> RightToken());
- ReportSemError(SemanticError::BLOCKED_CATCH_CLAUSE,
- clause -> formal_parameter -> LeftToken(),
- clause -> formal_parameter -> RightToken(),
- symbol -> Type() -> ContainingPackage() -> PackageName(),
- symbol -> Type() -> ExternalName(),
- loc.location);
- }
- else clause -> block -> is_reachable = true;
- }
- }
- }
-
- TryStatementStack().Pop();
- TryExceptionTableStack().Pop();
- if (TryExceptionTableStack().Top())
- {
- //
- // First, remove all the thrown exceptions that are caught by the enclosing
- // try statement. Then, add the remaining ones to the set that must be caught
- // by the immediately enclosing try statement.
- //
- for (int i = 0; i < thrown_exceptions.Length(); i++)
- exception_set -> RemoveElement(thrown_exceptions[i]);
- TryExceptionTableStack().Top() -> Union(*exception_set);
- }
- delete exception_set;
-
- //
- // A try statement cannot complete normally if it contains a finally
- // clause that cannot complete normally.
- //
- if (try_statement -> finally_clause_opt && (! try_statement -> finally_clause_opt -> block -> can_complete_normally))
- try_statement -> can_complete_normally = false;
-
- return;
- }
-
-
- void Semantic::ProcessEmptyStatement(Ast *stmt)
- {
- AstEmptyStatement *empty_statement = (AstEmptyStatement *) stmt;
-
- //
- // An empty statement can complete normally iff it is reachable.
- //
- empty_statement -> can_complete_normally = empty_statement -> is_reachable;
-
- return;
- }
-
-
- TypeSymbol *Semantic::GetLocalType(AstClassDeclaration *class_declaration)
- {
- NameSymbol *name_symbol = lex_stream -> NameSymbol(class_declaration -> identifier_token);
- TypeSymbol *type = LocalSymbolTable().Top() -> InsertNestedTypeSymbol(name_symbol);
-
- TypeSymbol *outermost_type = ThisType() -> outermost_type;
- if (! outermost_type -> local)
- outermost_type -> local = new SymbolSet;
-
- IntToWstring value(outermost_type -> local -> NameCount(name_symbol) + 1);
-
- int length = value.Length() + outermost_type -> NameLength() + 1 + name_symbol -> NameLength() + 1; // +1 for $,... +1 for $
- wchar_t *external_name = new wchar_t[length + 1]; // +1 for '\0';
- wcscpy(external_name, outermost_type -> Name());
- wcscat(external_name, StringConstant::US__DS);
- wcscat(external_name, value.String());
- wcscat(external_name, StringConstant::US__DS);
- wcscat(external_name, name_symbol -> Name());
-
- type -> SetACC_PRIVATE();
- type -> outermost_type = outermost_type;
- type -> SetExternalIdentity(control.FindOrInsertName(external_name, length));
- outermost_type -> local -> AddElement(type);
-
- delete [] external_name;
-
- return type;
- }
-
-
- void Semantic::ProcessClassDeclaration(Ast *stmt)
- {
- AstClassDeclaration *class_declaration = (AstClassDeclaration *) stmt;
- AstClassBody *class_body = class_declaration -> class_body;
-
- class_declaration -> MarkLocal(); // identify class as "statement" and assert that it is "reachable" and "can_complete_normally"
- if (! control.option.one_one)
- {
- ReportSemError(SemanticError::ONE_ONE_FEATURE,
- class_declaration -> LeftToken(),
- class_declaration -> RightToken());
- }
-
- CheckNestedTypeDuplication(state_stack.Top(), class_declaration -> identifier_token);
-
- NameSymbol *name_symbol = lex_stream -> NameSymbol(class_declaration -> identifier_token);
-
- TypeSymbol *inner_type = GetLocalType(class_declaration);
- inner_type -> outermost_type = ThisType() -> outermost_type;
- inner_type -> supertypes_closure = new SymbolSet;
- inner_type -> subtypes_closure = new SymbolSet;
- inner_type -> subtypes = new SymbolSet;
- inner_type -> semantic_environment = new SemanticEnvironment((Semantic *) this,
- inner_type,
- state_stack.Top());
- inner_type -> declaration = class_declaration;
- inner_type -> file_symbol = source_file_symbol;
- inner_type -> SetFlags(ProcessLocalClassModifiers(class_declaration));
- inner_type -> SetOwner(ThisMethod());
- //
- // Add 3 extra elements for padding. May need a default constructor and other support elements.
- //
- inner_type -> SetSymbolTable(class_body -> NumClassBodyDeclarations() + 3);
- inner_type -> SetLocation();
- inner_type -> SetSignature(control);
-
- if (StaticRegion())
- inner_type -> SetACC_STATIC();
- else inner_type -> InsertThis(0);
-
- class_declaration -> semantic_environment = inner_type -> semantic_environment; // save for processing bodies later.
-
- CheckClassMembers(inner_type, class_body);
-
- ProcessTypeHeaders(class_declaration);
-
- ProcessMembers(class_declaration -> semantic_environment, class_body);
- CompleteSymbolTable(class_declaration -> semantic_environment, class_declaration -> identifier_token, class_body);
- ProcessExecutableBodies(class_declaration -> semantic_environment, class_body);
-
- UpdateLocalConstructors(inner_type);
-
- return;
- }
-
-
- void Semantic::ProcessThisCall(AstThisCall *this_call)
- {
- TypeSymbol *this_type = ThisType(),
- *containing_type = this_type -> ContainingType();
-
- ExplicitConstructorInvocation() = this_call; // signal that we are about to process an explicit constructor invocation
-
- if (this_call -> base_opt)
- {
- if (! control.option.one_one)
- {
- ReportSemError(SemanticError::ONE_ONE_FEATURE,
- this_call -> base_opt -> LeftToken(),
- this_call -> dot_token_opt);
- }
-
- ProcessExpression(this_call -> base_opt);
-
- TypeSymbol *expr_type = this_call -> base_opt -> Type();
- if (expr_type != control.no_type)
- {
- if (! containing_type)
- {
- ReportSemError(SemanticError::TYPE_NOT_INNER_CLASS,
- this_call -> base_opt -> LeftToken(),
- this_call -> base_opt -> RightToken(),
- this_type -> ContainingPackage() -> PackageName(),
- this_type -> ExternalName(),
- expr_type -> ContainingPackage() -> PackageName(),
- expr_type -> ExternalName());
- this_call -> base_opt -> symbol = control.no_type;
- }
- //
- // 1.2 change. In 1.1, we used to allow access to any subclass of type. Now, there must
- // be a perfect match.
- //
- // else if (! expr_type -> IsSubclass(containing_type))
- //
- else if (expr_type != containing_type)
- {
- ReportSemError(SemanticError::INVALID_ENCLOSING_INSTANCE,
- this_call -> base_opt -> LeftToken(),
- this_call -> base_opt -> RightToken(),
- this_type -> ContainingPackage() -> PackageName(),
- this_type -> ExternalName(),
- containing_type -> ContainingPackage() -> PackageName(),
- containing_type -> ExternalName(),
- expr_type -> ContainingPackage() -> PackageName(),
- expr_type -> ExternalName());
- this_call -> base_opt -> symbol = control.no_type;
- }
- }
- }
- else // (! this_call -> base_opt)
- {
- if (this_type -> IsInner())
- this_call -> base_opt = CreateAccessToType(this_call, containing_type);
- }
-
- bool no_bad_argument = true;
-
- for (int i = 0; i < this_call -> NumArguments(); i++)
- {
- AstExpression *expr = (AstExpression *) this_call -> Argument(i);
- ProcessExpressionOrStringConstant(expr);
- no_bad_argument = no_bad_argument && (expr -> Type() != control.no_type);
- }
- if (no_bad_argument)
- {
- MethodSymbol *constructor = FindConstructor(this_type, this_call, this_call -> this_token, this_call -> RightToken());
- if (constructor)
- {
- this_call -> symbol = constructor;
-
- for (int i = 0; i < this_call -> NumArguments(); i++)
- {
- AstExpression *expr = this_call -> Argument(i);
- if (expr -> Type() != constructor -> FormalParameter(i) -> Type())
- this_call -> Argument(i) = ConvertToType(expr, constructor -> FormalParameter(i) -> Type());
- }
-
- for (int k = constructor -> NumThrows() - 1; k >= 0; k--)
- {
- TypeSymbol *exception = constructor -> Throws(k);
- if (! CatchableException(exception))
- {
- ReportSemError(SemanticError::CONSTRUCTOR_DOES_NOT_THROW_THIS_EXCEPTION,
- this_call -> this_token,
- this_call -> this_token,
- exception -> ContainingPackage() -> PackageName(),
- exception -> ExternalName());
- }
- }
-
- if (this_type -> IsLocal()) // a local type may use enclosed local variables?
- this_type -> AddLocalConstructorCallEnvironment(GetEnvironment(this_call));
-
- //
- // Note that there is no need to do access-checking as we are allowed,
- // within the body of a class, to invoke any other constructor or member
- // (private or otherwise) in that class.
- //
- }
- }
-
- ExplicitConstructorInvocation() = NULL; // signal that we are no longer processing an explicit constructor invocation
-
- this_call -> can_complete_normally = this_call -> is_reachable;
-
- return;
- }
-
-
- void Semantic::ProcessSuperCall(AstSuperCall *super_call)
- {
- TypeSymbol *this_type = ThisType();
- ExplicitConstructorInvocation() = super_call; // signal that we are about to process an explicit constructor invocation
-
- TypeSymbol *super_type = this_type -> super;
- if (! super_type) // this is only possible if we are compiling an illegal Object.java source file.
- super_type = control.Object();
-
- if (super_call -> base_opt)
- {
- if (! control.option.one_one)
- {
- ReportSemError(SemanticError::ONE_ONE_FEATURE,
- super_call -> base_opt -> LeftToken(),
- super_call -> dot_token_opt);
- }
-
- ProcessExpression(super_call -> base_opt);
-
- TypeSymbol *expr_type = super_call -> base_opt -> Type();
- if (expr_type != control.no_type)
- {
- TypeSymbol *containing_type = super_type -> ContainingType();
- if (! containing_type)
- {
- ReportSemError(SemanticError::SUPER_TYPE_NOT_INNER_CLASS,
- super_call -> base_opt -> LeftToken(),
- super_call -> base_opt -> RightToken(),
- super_type -> ContainingPackage() -> PackageName(),
- super_type -> ExternalName(),
- this_type -> ContainingPackage() -> PackageName(),
- this_type -> ExternalName(),
- expr_type -> ContainingPackage() -> PackageName(),
- expr_type -> ExternalName());
- super_call -> base_opt -> symbol = control.no_type;
- }
- //
- // 1.2 change. In 1.1, we used to allow access to any subclass of type. Now, there must
- // be a perfect match.
- //
- // else if (! expr_type -> IsSubclass(containing_type))
- //
- else if (expr_type != containing_type)
- {
- ReportSemError(SemanticError::INVALID_ENCLOSING_INSTANCE,
- super_call -> base_opt -> LeftToken(),
- super_call -> base_opt -> RightToken(),
- this_type -> ContainingPackage() -> PackageName(),
- this_type -> ExternalName(),
- containing_type -> ContainingPackage() -> PackageName(),
- containing_type -> ExternalName(),
- expr_type -> ContainingPackage() -> PackageName(),
- expr_type -> ExternalName());
- super_call -> base_opt -> symbol = control.no_type;
- }
- }
- }
- else // (! super_call -> base_opt)
- {
- if (super_type && super_type -> IsInner())
- super_call -> base_opt = CreateAccessToType(super_call, super_type -> ContainingType());
- }
-
- bool no_bad_argument = true;
- for (int i = 0; i < super_call -> NumArguments(); i++)
- {
- AstExpression *expr = (AstExpression *) super_call -> Argument(i);
- ProcessExpressionOrStringConstant(expr);
- no_bad_argument = no_bad_argument && (expr -> Type() != control.no_type);
- }
-
- if (this_type == control.Object())
- {
- super_call -> symbol = NULL;
- ReportSemError(SemanticError::MISPLACED_SUPER_EXPRESSION,
- super_call -> super_token,
- super_call -> super_token);
- }
- else if (no_bad_argument)
- {
- MethodSymbol *constructor = FindConstructor(super_type, super_call, super_call -> super_token, super_call -> RightToken());
-
- if (constructor)
- {
- //
- // No need to do a full access-check. Do the minimal stuff here !
- //
- if (constructor -> ACC_PRIVATE())
- {
- if (this_type -> outermost_type == super_type -> outermost_type)
- {
- if (! constructor -> LocalConstructor())
- {
- constructor = super_type -> GetReadAccessMethod(constructor);
-
- //
- // Add extra argument for read access constructor;
- //
- super_call -> AddNullArgument();
- }
- }
- else ReportSemError(SemanticError::PRIVATE_CONSTRUCTOR_NOT_ACCESSIBLE,
- super_call -> LeftToken(),
- super_call -> RightToken(),
- constructor -> Header(),
- super_type -> ContainingPackage() -> PackageName(),
- super_type -> ExternalName());
- }
- else if (! (constructor -> ACC_PUBLIC() || constructor -> ACC_PROTECTED()))
- {
- if (! (this_type -> outermost_type == super_type -> outermost_type ||
- super_type -> ContainingPackage() == this_package))
- ReportSemError(SemanticError::DEFAULT_CONSTRUCTOR_NOT_ACCESSIBLE,
- super_call -> super_token,
- super_call -> super_token,
- constructor -> Header(),
- super_type -> ContainingPackage() -> PackageName(),
- super_type -> ExternalName());
- }
-
- super_call -> symbol = constructor;
-
- if (super_call -> base_opt &&
- (super_call -> base_opt -> Type() != control.no_type) &&
- (super_call -> base_opt -> Type() != super_type -> ContainingType()))
- {
- assert(CanMethodInvocationConvert(super_type -> ContainingType(), super_call -> base_opt -> Type()));
-
- super_call -> base_opt = ConvertToType(super_call -> base_opt, super_type -> ContainingType());
- }
-
- for (int i = 0; i < super_call -> NumArguments(); i++)
- {
- AstExpression *expr = super_call -> Argument(i);
- if (expr -> Type() != constructor -> FormalParameter(i) -> Type())
- super_call -> Argument(i) = ConvertToType(expr, constructor -> FormalParameter(i) -> Type());
- }
-
- //
- // Make sure that the throws signature of the constructor is processed.
- //
- for (int k = constructor -> NumThrows() - 1; k >= 0; k--)
- {
- TypeSymbol *exception = constructor -> Throws(k);
- if (! CatchableException(exception))
- {
- ReportSemError(SemanticError::CONSTRUCTOR_DOES_NOT_THROW_SUPER_EXCEPTION,
- super_call -> LeftToken(),
- super_call -> RightToken(),
- this_type -> Name(),
- exception -> ContainingPackage() -> PackageName(),
- exception -> ExternalName(),
- constructor -> containing_type -> ContainingPackage() -> PackageName(),
- constructor -> containing_type -> ExternalName());
- }
- }
-
- if (super_type -> IsLocal()) // a local type may use enclosed local variables?
- {
- if (super_type -> LocalClassProcessingCompleted())
- {
- assert(ThisMethod() -> LocalConstructor() && (! ThisMethod() -> IsGeneratedLocalConstructor()));
-
- assert(constructor -> LocalConstructor() && (! constructor -> IsGeneratedLocalConstructor()));
-
- super_call -> symbol = constructor -> LocalConstructor();
-
- //
- // Recall that as a side-effect, when a local shadow is created in a type
- // an argument that will be used to initialize the local shadow that has
- // the same identity must be passed to every constructor in the type. Since
- // we are currently processing a constructor, such an argument must be available.
- //
- BlockSymbol *block_symbol = ThisMethod() -> LocalConstructor() -> block_symbol;
- for (int i = (super_type -> ACC_STATIC() ? 0 : 1); i < super_type -> NumConstructorParameters(); i++)
- {
- VariableSymbol *local = super_type -> ConstructorParameter(i) -> accessed_local,
- *local_shadow = this_type -> FindOrInsertLocalShadow(local);
-
- AstSimpleName *simple_name = compilation_unit -> ast_pool -> GenSimpleName(super_call -> super_token);
- simple_name -> symbol = block_symbol -> FindVariableSymbol(local_shadow -> Identity());
-
- assert(simple_name -> symbol);
-
- super_call -> AddLocalArgument(simple_name);
- }
- }
- else // are we currently within the body of the type in question ?
- {
- super_type -> AddLocalConstructorCallEnvironment(GetEnvironment(super_call));
- }
- }
- }
- }
-
- ExplicitConstructorInvocation() = NULL; // signal that we are no longer processing an explicit constructor invocation
-
- super_call -> can_complete_normally = super_call -> is_reachable;
-
- return;
- }
-
-
- void Semantic::CheckThrow(AstExpression *throw_expression)
- {
- TypeSymbol *throw_type = throw_expression -> symbol -> TypeCast();
-
- assert(throw_type);
-
- if (throw_type -> ACC_INTERFACE())
- {
- ReportSemError(SemanticError::NOT_A_CLASS,
- throw_expression -> LeftToken(),
- throw_expression -> RightToken(),
- throw_type -> ContainingPackage() -> PackageName(),
- throw_type -> ExternalName());
- }
- else if (! throw_type -> IsSubclass(control.Throwable()))
- {
- ReportSemError(SemanticError::TYPE_NOT_THROWABLE,
- throw_expression -> LeftToken(),
- throw_expression -> RightToken(),
- throw_type -> ContainingPackage() -> PackageName(),
- throw_type -> ExternalName());
- }
-
- return;
- }
-
-
- void Semantic::ProcessMethodBody(AstMethodDeclaration *method_declaration)
- {
- MethodSymbol *this_method = ThisMethod();
-
- for (int k = 0; k < method_declaration -> NumThrows(); k++)
- CheckThrow(method_declaration -> Throw(k));
-
- AstMethodDeclarator *method_declarator = method_declaration -> method_declarator;
-
- if (! method_declaration -> method_body -> EmptyStatementCast())
- {
- //
- // The block that is the body of a method is reachable
- //
- AstBlock *block_body;
-
- //
- // The body of a method must be a regular block. If instead, it
- // is a constructor block, mark the compilation unit as a bad
- // compilation so that the parser can properly diagnose this
- // problem later.
- //
- AstConstructorBlock *constructor_block = method_declaration -> method_body -> ConstructorBlockCast();
- if (constructor_block)
- {
- compilation_unit -> kind = Ast::BAD_COMPILATION; // invalidate the compilation unit
-
- constructor_block -> is_reachable = true;
- block_body = constructor_block -> block;
-
- //
- // If the parser recognizes the body of a method as a ConstructorBlock
- // then it must have an explicit_constructor_invocation.
- //
- AstThisCall *this_call = constructor_block -> explicit_constructor_invocation_opt -> ThisCallCast();
- if (this_call)
- {
- this_call -> is_reachable = true;
- //
- // Do not process the explicit constructor invocation as this could
- // cause problems with assertions (e.g. for inner classes) that will
- // turn out not to be true.
- //
- // ProcessThisCall(this_call);
- //
- block_body -> is_reachable = this_call -> can_complete_normally;
- }
- else
- {
- AstSuperCall *super_call = (AstSuperCall *) constructor_block -> explicit_constructor_invocation_opt;
- super_call -> is_reachable = true;
- //
- // Do not process the explicit constructor invocation as this could
- // cause problems with assertions (e.g. for inner classes) that will
- // turn out not to be true.
- //
- // ProcessSuperCall(super_call);
- //
- block_body -> is_reachable = super_call -> can_complete_normally;
- }
- }
- else
- {
- block_body = (AstBlock *) method_declaration -> method_body;
- block_body -> is_reachable = true;
- }
-
- block_body -> block_symbol = this_method -> block_symbol;
- block_body -> nesting_level = LocalBlockStack().Size();
- LocalBlockStack().Push(block_body);
-
- ProcessBlockStatements(block_body);
-
- LocalBlockStack().Pop();
-
- if (block_body -> can_complete_normally)
- {
- if (this_method -> Type() == control.void_type)
- {
- AstReturnStatement *return_statement = compilation_unit -> ast_pool -> GenReturnStatement();
- return_statement -> return_token = block_body -> right_brace_token;
- return_statement -> expression_opt = NULL;
- return_statement -> semicolon_token = block_body -> right_brace_token;
- return_statement -> is_reachable = true;
- block_body -> can_complete_normally = false;
- block_body -> AddStatement(return_statement);
- }
- else
- {
- ReportSemError(SemanticError::TYPED_METHOD_WITH_NO_RETURN,
- method_declaration -> type -> LeftToken(),
- method_declaration -> method_declarator -> identifier_token,
- this_method -> Header(),
- this_method -> Type() -> Name());
- }
- }
-
- if (this_method -> ACC_ABSTRACT() || this_method -> ACC_NATIVE())
- {
- ReportSemError(SemanticError::ABSTRACT_METHOD_WITH_BODY,
- method_declaration -> LeftToken(),
- method_declaration -> RightToken(),
- this_method -> Header());
- }
- }
- else if (! (this_method -> ACC_ABSTRACT() || this_method -> ACC_NATIVE()))
- {
- ReportSemError(SemanticError::NON_ABSTRACT_METHOD_WITHOUT_BODY,
- method_declaration -> LeftToken(),
- method_declaration -> RightToken(),
- this_method -> Header());
- }
-
- this_method -> block_symbol -> CompressSpace(); // space optimization
-
- return;
- }
-
-
- void Semantic::ProcessConstructorBody(AstConstructorDeclaration *constructor_declaration, bool body_reachable)
- {
- TypeSymbol *this_type = ThisType();
- MethodSymbol *this_method = ThisMethod();
-
- for (int k = 0; k < constructor_declaration -> NumThrows(); k++)
- CheckThrow(constructor_declaration -> Throw(k));
-
- AstMethodDeclarator *constructor_declarator = constructor_declaration -> constructor_declarator;
-
- //
- // The block that is the body of a constructor is reachable
- //
- AstConstructorBlock *constructor_block = constructor_declaration -> constructor_body;
-
- constructor_block -> is_reachable = true;
- AstBlock *block_body = constructor_block -> block;
- AstThisCall *this_call = NULL;
- AstSuperCall *super_call = NULL;
- TypeSymbol *super_type = this_type -> super;
-
- if (constructor_block -> explicit_constructor_invocation_opt)
- {
- this_call = constructor_block -> explicit_constructor_invocation_opt -> ThisCallCast();
- super_call = constructor_block -> explicit_constructor_invocation_opt -> SuperCallCast();
- }
- else if (super_type)
- {
- LexStream::TokenIndex loc = block_body -> LeftToken();
- super_call = compilation_unit -> ast_pool -> GenSuperCall();
- super_call -> base_opt = NULL;
- super_call -> dot_token_opt = loc;
- super_call -> super_token = loc;
- super_call -> left_parenthesis_token = loc;
- super_call -> right_parenthesis_token = loc;
- super_call -> semicolon_token = loc;
-
- constructor_block -> explicit_constructor_invocation_opt = super_call;
-
- if (super_type -> IsInner() && (! this_type -> CanAccess(super_type -> ContainingType())))
- {
- ReportSemError(SemanticError::ENCLOSING_INSTANCE_NOT_ACCESSIBLE,
- constructor_declaration -> constructor_declarator -> LeftToken(),
- constructor_declaration -> constructor_declarator -> RightToken(),
- super_type -> ContainingType() -> ContainingPackage() -> PackageName(),
- super_type -> ContainingType() -> ExternalName());
- }
- }
-
- //
- // If the constructor starts with an explicit_constructor_invocation, either
- // one specified by the user or generated, we process it and set up the proper
- // local environment, if appropriate...
- //
- if (constructor_block -> explicit_constructor_invocation_opt)
- {
- //
- // If we are processing a local constructor, set up the generated environment...
- //
- if (this_type -> IsLocal())
- {
- LocalSymbolTable().Pop();
-
- assert(this_method -> LocalConstructor() && (! this_method -> IsGeneratedLocalConstructor()));
-
- LocalSymbolTable().Push(this_method -> LocalConstructor() -> block_symbol -> Table());
- }
-
- if (this_call)
- {
- this_call -> is_reachable = true;
- ProcessThisCall(this_call);
- }
- else
- {
- assert(super_call);
-
- super_call -> is_reachable = true;
- ProcessSuperCall(super_call);
- }
-
- //
- // If we are processing a local constructor, restore its original environment...
- //
- if (this_type -> IsLocal())
- {
- LocalSymbolTable().Pop();
- LocalSymbolTable().Push(this_method -> block_symbol -> Table());
- }
- }
-
- if (! (body_reachable || (constructor_block -> explicit_constructor_invocation_opt &&
- constructor_block -> explicit_constructor_invocation_opt -> ThisCallCast())))
- {
- ReportSemError(SemanticError::UNREACHABLE_CONSTRUCTOR_BODY,
- constructor_declaration -> LeftToken(),
- constructor_declaration -> RightToken());
- }
-
- //
- // Guess that the number of elements will not exceed the number of statements.
- //
- int table_size = block_body -> NumStatements();
- BlockSymbol *block = LocalSymbolTable().Top() -> InsertBlockSymbol(table_size);
- //
- // enclosing_block is not present only when we are processing the block of a static initializer
- //
- block -> max_variable_index = this_method -> block_symbol -> max_variable_index;
- LocalSymbolTable().Push(block -> Table());
-
- block_body -> is_reachable = true;
- block_body -> block_symbol = block;
- block_body -> nesting_level = LocalBlockStack().Size();
- LocalBlockStack().Push(block_body);
-
- ProcessBlockStatements(block_body);
-
- if (block_body -> can_complete_normally)
- {
- AstReturnStatement *return_statement = compilation_unit -> ast_pool -> GenReturnStatement();
- return_statement -> return_token = block_body -> right_brace_token;
- return_statement -> expression_opt = NULL;
- return_statement -> semicolon_token = block_body -> right_brace_token;
- return_statement -> is_reachable = true;
- block_body -> can_complete_normally = false;
- block_body -> AddStatement(return_statement);
- }
-
- constructor_block -> can_complete_normally = block_body -> can_complete_normally;
-
- LocalBlockStack().Pop();
- LocalSymbolTable().Pop();
-
- //
- // Update the local variable info for the main block associated with this constructor.
- //
- if (this_method -> block_symbol -> max_variable_index < block -> max_variable_index)
- this_method -> block_symbol -> max_variable_index = block -> max_variable_index;
-
- block -> CompressSpace(); // space optimization
-
- return;
- }
-
-
- void Semantic::ProcessExecutableBodies(SemanticEnvironment *environment, AstClassBody *class_body)
- {
- state_stack.Push(environment);
- TypeSymbol *this_type = ThisType();
-
- assert(this_type -> HeaderProcessed());
- assert(this_type -> ConstructorMembersProcessed());
- assert(this_type -> MethodMembersProcessed());
- assert(this_type -> FieldMembersProcessed());
-
- ThisVariable() = NULL; // All variable declarations have already been processed
-
- //
- // Compute the set of instance final variables declared by the user in this type
- // as well as the set of instance final variables that have not yet been initialized.
- //
- Tuple<VariableSymbol *> finals(this_type -> NumVariableSymbols()),
- unassigned_finals(this_type -> NumVariableSymbols());
- for (int k = 0; k < this_type -> NumVariableSymbols(); k++)
- {
- VariableSymbol *variable_symbol = this_type -> VariableSym(k);
- if (variable_symbol -> ACC_FINAL() && variable_symbol -> declarator)
- {
- finals.Next() = variable_symbol;
-
- if (! variable_symbol -> IsDefinitelyAssigned())
- unassigned_finals.Next() = variable_symbol;
- }
- }
-
- AstBlock *last_block_body = (class_body -> NumBlocks() > 0 ? class_body -> Block(class_body -> NumBlocks() - 1)
- : (AstBlock *) NULL);
- if (class_body -> NumConstructors() == 0)
- {
- //
- // Issue an error for each unassigned final.
- //
- for (int k = 0; k < unassigned_finals.Length(); k++)
- {
- ReportSemError(SemanticError::UNINITIALIZED_FINAL_VARIABLE,
- unassigned_finals[k] -> declarator -> LeftToken(),
- unassigned_finals[k] -> declarator -> RightToken());
- }
-
- //
- // Process the body of the default constructor, if there is one.
- // (An anonymous class does not yet have a default constructor at this point.)
- //
- AstConstructorDeclaration *constructor_decl = class_body -> default_constructor;
- if (constructor_decl)
- {
- ThisMethod() = constructor_decl -> constructor_symbol;
-
- LocalSymbolTable().Push(ThisMethod() -> block_symbol -> Table());
- LocalBlockStack().max_size = 0;
- ProcessConstructorBody(constructor_decl, ((! last_block_body) || last_block_body -> can_complete_normally));
- LocalSymbolTable().Pop();
- ThisMethod() -> max_block_depth = LocalBlockStack().max_size;
- }
- }
- else
- {
- for (int i = 0; i < class_body -> NumConstructors(); i++)
- {
- AstConstructorDeclaration *constructor_decl = class_body -> Constructor(i);
-
- ThisMethod() = constructor_decl -> constructor_symbol;
- MethodSymbol *this_method = ThisMethod();
- if (this_method)
- {
- for (int l = 0; l < this_method -> NumFormalParameters(); l++)
- {
- VariableSymbol *parm = this_method -> FormalParameter(l);
- AstVariableDeclaratorId *name = parm -> declarator -> variable_declarator_name;
-
- SemanticEnvironment *where_found;
- Tuple<VariableSymbol *> variables_found(2);
- SearchForVariableInEnvironment(variables_found, where_found, state_stack.Top(),
- parm -> Identity(),
- name -> identifier_token);
- VariableSymbol *symbol = (variables_found.Length() > 0 ? variables_found[0] : (VariableSymbol *) NULL);
- if (symbol && symbol -> IsLocal())
- {
- ReportSemError(SemanticError::DUPLICATE_LOCAL_VARIABLE_DECLARATION,
- name -> identifier_token,
- name -> identifier_token,
- parm -> Name());
- }
- }
-
- AstConstructorBlock *constructor_block = constructor_decl -> constructor_body;
- if (constructor_block -> explicit_constructor_invocation_opt &&
- constructor_block -> explicit_constructor_invocation_opt -> ThisCallCast())
- {
- for (int j = 0; j < unassigned_finals.Length(); j++)
- unassigned_finals[j] -> MarkDefinitelyAssigned();
- }
- else
- {
- for (int j = 0; j < unassigned_finals.Length(); j++)
- unassigned_finals[j] -> MarkNotDefinitelyAssigned();
- }
-
- LocalSymbolTable().Push(this_method -> block_symbol -> Table());
- LocalBlockStack().max_size = 0;
-
- int start_num_errors = NumErrors();
- ProcessConstructorBody(constructor_decl, ((! last_block_body) || last_block_body -> can_complete_normally));
-
- LocalSymbolTable().Pop();
- this_method -> max_block_depth = LocalBlockStack().max_size;
-
- if (NumErrors() == start_num_errors)
- DefiniteConstructorBody(constructor_decl, finals);
-
- for (int k = 0; k < unassigned_finals.Length(); k++)
- {
- VariableSymbol *variable_symbol = unassigned_finals[k];
- if (! variable_symbol -> IsDefinitelyAssigned())
- {
- ReportSemError(SemanticError::UNINITIALIZED_FINAL_VARIABLE_IN_CONSTRUCTOR,
- constructor_decl -> LeftToken(),
- constructor_decl -> RightToken(),
- variable_symbol -> Name());
- }
- }
- }
- }
-
- for (int l = 0; l < this_type -> NumPrivateAccessConstructors(); l++)
- {
- ThisMethod() = this_type -> PrivateAccessConstructor(l);
- MethodSymbol *this_method = ThisMethod();
- AstConstructorDeclaration *constructor_decl = (AstConstructorDeclaration *)
- this_method -> method_or_constructor_declaration;
-
- LocalSymbolTable().Push(this_method -> block_symbol -> Table());
- LocalBlockStack().max_size = 0;
- ProcessConstructorBody(constructor_decl, true);
- LocalSymbolTable().Pop();
- this_method -> max_block_depth = LocalBlockStack().max_size;
- }
-
- ConstructorCycleChecker cycle_checker(class_body);
- }
-
- for (int j = 0; j < class_body -> NumMethods(); j++)
- {
- AstMethodDeclaration *method_decl = class_body -> Method(j);
-
- ThisMethod() = method_decl -> method_symbol;
- MethodSymbol *this_method = ThisMethod();
- if (this_method)
- {
- //
- // TODO: Confirm that this new test is indeed necessary. In 1.0, a more restricted test was used...
- //
- for (int i = 0; i < this_method -> NumFormalParameters(); i++)
- {
- VariableSymbol *parm = this_method -> FormalParameter(i);
- AstVariableDeclaratorId *name = parm -> declarator -> variable_declarator_name;
-
- SemanticEnvironment *where_found;
- Tuple<VariableSymbol *> variables_found(2);
- SearchForVariableInEnvironment(variables_found, where_found, state_stack.Top(),
- parm -> Identity(),
- name -> identifier_token);
- VariableSymbol *symbol = (variables_found.Length() > 0 ? variables_found[0] : (VariableSymbol *) NULL);
- if (symbol && symbol -> IsLocal())
- {
- ReportSemError(SemanticError::DUPLICATE_LOCAL_VARIABLE_DECLARATION,
- name -> identifier_token,
- name -> identifier_token,
- parm -> Name());
- }
- }
-
- LocalSymbolTable().Push(this_method -> block_symbol -> Table());
- LocalBlockStack().max_size = 0;
-
- int start_num_errors = NumErrors();
- ProcessMethodBody(method_decl);
-
- LocalSymbolTable().Pop();
- this_method -> max_block_depth = LocalBlockStack().max_size;
-
- if (NumErrors() == start_num_errors)
- DefiniteMethodBody(method_decl, finals);
- }
- }
-
- //
- // Mark all instance variables and constructor parameters final.
- //
- for (int i = 0; i < this_type -> NumConstructorParameters(); i++)
- this_type -> ConstructorParameter(i) -> SetACC_FINAL();
-
- for (int l = 0; l < this_type -> NumEnclosingInstances(); l++)
- this_type -> EnclosingInstance(l) -> SetACC_FINAL();
-
- //
- // We are done with all the methods, indicate that there is no method
- // being currently compiled in this environment.
- //
- ThisMethod() = NULL;
-
- //
- // Recursively process all inner types
- //
- for (int m = 0; m < class_body -> NumNestedClasses(); m++)
- {
- AstClassDeclaration *class_declaration = class_body -> NestedClass(m);
- if (class_declaration -> semantic_environment)
- ProcessExecutableBodies(class_declaration -> semantic_environment, class_declaration -> class_body);
- }
-
- for (int n = 0; n < class_body -> NumNestedInterfaces(); n++)
- {
- if (class_body -> NestedInterface(n) -> semantic_environment)
- ProcessExecutableBodies(class_body -> NestedInterface(n));
- }
-
- state_stack.Pop();
-
- return;
- }
-
-
- void Semantic::ProcessExecutableBodies(AstInterfaceDeclaration *interface_declaration)
- {
- state_stack.Push(interface_declaration -> semantic_environment);
- TypeSymbol *this_type = ThisType();
-
- assert(this_type -> HeaderProcessed());
- assert(this_type -> MethodMembersProcessed());
- assert(this_type -> FieldMembersProcessed());
-
- for (int k = 0; k < this_type -> NumVariableSymbols(); k++)
- {
- VariableSymbol *variable_symbol = this_type -> VariableSym(k);
- if (! variable_symbol -> IsDefinitelyAssigned())
- {
- ReportSemError(SemanticError::UNINITIALIZED_FINAL_VARIABLE,
- variable_symbol -> declarator -> LeftToken(),
- variable_symbol -> declarator -> RightToken());
- }
- }
-
- //
- // Recursively process all inner types
- //
- for (int m = 0; m < interface_declaration -> NumNestedClasses(); m++)
- {
- AstClassDeclaration *class_declaration = interface_declaration -> NestedClass(m);
- if (class_declaration -> semantic_environment)
- ProcessExecutableBodies(class_declaration -> semantic_environment, class_declaration -> class_body);
- }
-
- for (int n = 0; n < interface_declaration -> NumNestedInterfaces(); n++)
- {
- if (interface_declaration -> NestedInterface(n) -> semantic_environment)
- ProcessExecutableBodies(interface_declaration -> NestedInterface(n));
- }
-
- state_stack.Pop();
-
- return;
- }
-